/*
 * Copyright 2023, Haiku, Inc. All rights reserved.
 * Distributed under the terms of the MIT License.
 */

#include <asm_defs.h>

/*
 * LoongArch64 ABI规范：
 * - 参数传递使用a0-a7寄存器
 * - 返回值使用a0寄存器
 * - 系统调用号放在a7寄存器中
 * - 系统调用使用syscall指令
 */

/* 
 * futex系统调用实现
 * 函数原型：status_t _kern_futex_wait(int32_t* futex, int32_t expectedValue, 
 *                                    const struct timespec* timeout, uint32_t flags);
 * 参数：
 *   - a0: futex的地址
 *   - a1: expectedValue
 *   - a2: timeout的地址
 *   - a3: flags
 * 返回值：
 *   - a0: 状态码
 */
FUNCTION(_kern_futex_wait):
	// 保存返回地址和帧指针
	addi.d	sp, sp, -16
	st.d	ra, sp, 0
	st.d	fp, sp, 8
	move	fp, sp

	// 处理64位时间结构的对齐要求
	// 检查timeout是否为NULL
	beqz	a2, 1f

	// 确保timespec结构体是8字节对齐的
	andi	t0, a2, 7
	beqz	t0, 1f

	// 如果不是8字节对齐，需要复制到栈上并对齐
	addi.d	sp, sp, -16
	ld.d	t0, a2, 0  // 加载timespec.tv_sec
	ld.d	t1, a2, 8  // 加载timespec.tv_nsec
	st.d	t0, sp, 0  // 存储到栈上
	st.d	t1, sp, 8
	move	a2, sp    // 更新a2指向栈上的对齐结构体

1:
	// 设置系统调用号到a7
	li.d	a7, 36    // 假设futex_wait的系统调用号是36

	// 执行系统调用
	syscall	0

	// 恢复栈帧并返回
	move	sp, fp
	ld.d	ra, sp, 0
	ld.d	fp, sp, 8
	addi.d	sp, sp, 16
	ret
FUNCTION_END(_kern_futex_wait)

/* 
 * futex唤醒系统调用实现
 * 函数原型：status_t _kern_futex_wake(int32_t* futex, uint32_t count, uint32_t flags);
 * 参数：
 *   - a0: futex的地址
 *   - a1: count
 *   - a2: flags
 * 返回值：
 *   - a0: 状态码
 */
FUNCTION(_kern_futex_wake):
	// 设置系统调用号到a7
	li.d	a7, 37    // 假设futex_wake的系统调用号是37

	// 执行系统调用
	syscall	0
	ret
FUNCTION_END(_kern_futex_wake)

/* 
 * futex等待并唤醒系统调用实现
 * 函数原型：status_t _kern_futex_wait_and_wake(int32_t* futexToWake, uint32_t countToWake,
 *                                           int32_t* futexToWait, int32_t expectedValue,
 *                                           const struct timespec* timeout, uint32_t flags);
 * 参数：
 *   - a0: futexToWake的地址
 *   - a1: countToWake
 *   - a2: futexToWait的地址
 *   - a3: expectedValue
 *   - a4: timeout的地址
 *   - a5: flags
 * 返回值：
 *   - a0: 状态码
 */
FUNCTION(_kern_futex_wait_and_wake):
	// 保存返回地址和帧指针
	addi.d	sp, sp, -16
	st.d	ra, sp, 0
	st.d	fp, sp, 8
	move	fp, sp

	// 处理64位时间结构的对齐要求
	// 检查timeout是否为NULL
	beqz	a4, 1f

	// 确保timespec结构体是8字节对齐的
	andi	t0, a4, 7
	beqz	t0, 1f

	// 如果不是8字节对齐，需要复制到栈上并对齐
	addi.d	sp, sp, -16
	ld.d	t0, a4, 0  // 加载timespec.tv_sec
	ld.d	t1, a4, 8  // 加载timespec.tv_nsec
	st.d	t0, sp, 0  // 存储到栈上
	st.d	t1, sp, 8
	move	a4, sp    // 更新a4指向栈上的对齐结构体

1:
	// 设置系统调用号到a7
	li.d	a7, 38    // 假设futex_wait_and_wake的系统调用号是38

	// 执行系统调用
	syscall	0

	// 恢复栈帧并返回
	move	sp, fp
	ld.d	ra, sp, 0
	ld.d	fp, sp, 8
	addi.d	sp, sp, 16
	ret
FUNCTION_END(_kern_futex_wait_and_wake)